package org.dy.servlet.mvc.crud;

import java.util.ArrayList;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.dy.db.model.FieldInfo;
import org.dy.db.model.Row;
import org.dy.db.model.crud.CrudModel;
import org.dy.servlet.mvc.ModelAndView;
import org.dy.servlet.mvc.support.ActionOptException;
import org.dy.servlet.mvc.support.ActionUtils;
import org.dy.servlet.mvc.support.BaseAction;

public class CrudAction extends BaseAction {
	
	final String operateTypeList = "list|listbyquery|listinpage|listpagebyquery|viewone|nextone" +
			"|exportpdf|exportexcel|addform|addpost|updatepost|deletepost|autocomplete|checkunique";
	
	private String[] getModelInfo(String str){
		String[] res = str.split("-");
		if(res.length != 3)
			return null;
		return res;
	}
	
	/*
	 * parameter post or get
	 * 
	 * eg. model=app_name-module_name-model_name
	 */
	protected String getParamModel(HttpServletRequest req){

		return super.getDefaultParameter(req, "model", "-");
	}
	
	protected String getParamOperate(HttpServletRequest req){
		return super.getDefaultParameter(req, "opt", "-");
	}
	
	protected CrudModel getModel(HttpServletRequest req){
		String[] info = getModelInfo(getParamModel(req));
		if(info == null)
			return null;
		String configDirPath = req.getRealPath("crud/config");
		return new CrudModel(configDirPath, info[0], info[1], info[2]);
	}
	
	/*
	 * 
	 */
	protected Row getParamField(HttpServletRequest req, CrudModel model){
		Map<String,String> map = super.getSimiliarParameters(req, "field_");
		FieldInfo pf = getParamOneField(req, model, "pk_");
		if(map.isEmpty())
			return null;
		
		Row row = new Row();
		if(pf != null && pf.isPk())
			row.getFields().add(pf);
		Set<String> set = map.keySet();
		for(String key:set){
			FieldInfo fi = model.getTh().getFieldByName(key);
			// change primary key if possible
			if(fi.isPk()){
				if(pf != null && pf.isPk()){
					fi.setPk(false);
					row.getFields().add(pf);
					row.setPkName(pf.getName());
				}
			}
			// from field_
			fi.setValue(map.get(key));
			row.getFields().add(fi);
		}
		
		return row;
	}
	
	protected FieldInfo getParamOneField(HttpServletRequest req, CrudModel model, String pre){
		Map<String,String> map = super.getSimiliarParameters(req, pre);
		
		Set<String> set = map.keySet();
		for(String key:set){
			FieldInfo fi = model.getTh().getFieldByName(key);
			if(fi != null){
				fi.setValue(map.get(key));
				return fi;
			}
		}
		return null;
	}
	
	@Override
	public ModelAndView processInternal(HttpServletRequest request, 
			HttpServletResponse response) throws ActionOptException {
		// TODO Auto-generated method stub
		CrudModel model = getModel(request);
		if(model == null){
			return new CrudErrorView("no_model_match");
		}
		ModelAndView mv = new ModelAndView();
		
		// request query string
		StringBuffer url = request.getRequestURL();
		if (request.getQueryString() != null) {
			url.append('?');
			url.append(request.getQueryString());
		}
		String reqUrl = url.toString();
		
		// model operation
		String optType = getParamOperate(request);
		ArrayList optList = ActionUtils.stringToArrayList(operateTypeList);
		if(!optList.contains(optType)){
			// throw new CrudOptException("No Such Model Operation " + optType);
			optType = "list";
		}
		
		// query
		if(optType.equals("list")){
			mv.addObject("list", model.listAll());
			mv.setView("crud_list_all");
			
		}else if(optType.equals("autocomplete")){
			String fields = super.getDefaultParameter(request, "fields", "*");
			mv.addObject("list", model.listFields(fields));
			mv.addObject("field", super.getDefaultParameter(request, "field", ""));
			mv.setView("crud_acp");
			
		}else if(optType.equals("listbyquery")){
			Row row = this.getParamField(request, model);
			if(!row.valid()){
				return new CrudErrorView("parameter_invalid");
			}
			mv.addObject("list", model.listByQuery(row));
			mv.setView("crud_list_all");
			
		}else if(optType.equals("listinpage")){			
			int npp = super.getDefaultIntParameter(request, "npp", 20);
			int cp = super.getDefaultIntParameter(request, "cp", 1);
			
			if(reqUrl.indexOf("cp") != -1){
				reqUrl = reqUrl.replaceFirst("&cp=\\d+", "");
			}
			
			if(reqUrl.indexOf("npp") != -1){
				reqUrl = reqUrl.replaceFirst("&npp=\\d+", "");			
			}
			
			mv.addObject("page", model.listInPage(cp, npp));
			mv.addObject("req_url", reqUrl);
			mv.setView("crud_list_in_page");
			
		}else if(optType.equals("listpagebyquery")){			
			int npp = super.getDefaultIntParameter(request, "npp", 20);
			int cp = super.getDefaultIntParameter(request, "cp", 1);
			
			if(reqUrl.indexOf("cp") != -1){
				reqUrl = reqUrl.replaceFirst("&cp=\\d+", "");
			}
			
			if(reqUrl.indexOf("npp") != -1){
				reqUrl = reqUrl.replaceFirst("&npp=\\d+", "");
			}
			
			Row row = this.getParamField(request, model);
			if(!row.valid()){
				return new CrudErrorView("parameter_invalid");
			}
			mv.addObject("page", model.listPageByQuery(row, cp, npp));
			mv.addObject("req_url", reqUrl);
			mv.setView("crud_list_in_page");
			
		}else if(optType.equals("viewone")){
			Row rrow = this.getParamField(request, model);
			if(!rrow.valid()){
				return new CrudErrorView("parameter_invalid");
			}
			if(rrow == null){
				String value = super.getParameter(request, "value");
				if(value == null || value.trim().equals(""))
					return new CrudErrorView("parameter_required");
				else{
					FieldInfo fi = model.getTh().getPkInfo();
					if(fi == null)
						return new CrudErrorView("parameter_required");
					else{
						fi.setValue(value);
						rrow = new Row();
						rrow.getFields().add(fi);
					}
				}
			}
			
			mv.addObject("row", model.getOne(rrow));
			mv.setView("crud_view_one");
			
		}else if(optType.equals("checkunique")){
			FieldInfo fi = this.getParamOneField(request, model, "u_");
			if(fi.isPk()){
				Row row = model.getOne(fi);
				if(row != null)
					mv.addObject("r", 1);
			}
			
			mv.setView("crud_check_unique");
			
		}else if(optType.equals("nextone")){
			int npp = super.getDefaultIntParameter(request, "npp", 1);
			int cp = super.getDefaultIntParameter(request, "cp", 1);
			
			if(reqUrl.indexOf("cp") != -1){
				reqUrl = reqUrl.replaceFirst("&cp=\\d+", "");
			}
			
			if(reqUrl.indexOf("npp") != -1){
				reqUrl = reqUrl.replaceFirst("&npp=\\d+", "");
			}
			
			mv.addObject("page", model.listInPage(cp, npp));
			mv.addObject("req_url", reqUrl);
			mv.setView("crud_next_one");
			
		}else if(optType.equals("exportpdf")){
			
		}else if(optType.equals("exportexcel")){
		
		// add
		}else if(optType.equals("addform")){
			if(model.canAddOrUpdate()){
				mv.addObject("th", model.getTh());
				mv.setView("crud_add_form");
			}else{
				return new CrudErrorView("add_no_support");
			}
			
		}else if(optType.equals("addpost")){
			if(model.canAddOrUpdate()){
				Row row = this.getParamField(request, model);
				if(!row.valid()){
					return new CrudErrorView("parameter_invalid");
				}
				model.create(row);
				mv.addObject("row", row);
				mv.setView("crud_add_post");
			}else{
				return new CrudErrorView("add_no_support");
			}
			
		}else if(optType.equals("updatepost")){
			if(model.canAddOrUpdate()){
				Row row = this.getParamField(request, model);
				if(!row.valid()){
					return new CrudErrorView("parameter_invalid");
				}
				model.update(row);	
				mv.addObject("row", row);
				mv.setView("crud_update_post");
			}else{
				return new CrudErrorView("update_no_support");
			}
			
		}else if(optType.equals("deletepost")){
			if(model.canDelete()){
				Row row = this.getParamField(request, model);
				if(!row.valid()){
					return new CrudErrorView("parameter_invalid");
				}
				model.delete(row);
				mv.setView("crud_delete_post");
			}else{
				return new CrudErrorView("delete_no_support");
			}
			 
		}else{
			
		}
		
		mv.addObject("app_name", model.getApp());
		mv.addObject("module_name", model.getModule());
		mv.addObject("model_name", model.getName());
		mv.addObject("model_des", model.getDes());
		mv.addObject("model_mod", model.getTh().getMod());
		
		mv.addObject("model_crud_url", getParamModel(request));
		return mv;
	}
}
